﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using System.IO;
using System.Xml;
using System.Text.RegularExpressions;
using System.Threading;
using System.Web;
using System.Xml.Linq;
using Microsoft.Crm.SdkTypeProxy;
using Microsoft.Crm.Sdk;
using VS4CRM.Lib.Model;


namespace VS4CRM.Lib
{
    public class ScriptUploader
    {
        private XElement _customizations;
        private string _exportedCustomisations;
        private IProjectHandler _projectHandler;

        private const string FORMAT_IMPORT_EPORT_PARAM = "<importexportxml><entities>{0}</entities><nodes>{1}</nodes><securityroles></securityroles><settings></settings><workflows>{2}</workflows></importexportxml>";

        private const string EntityNameXPath = "/ImportExportXml/Entities/Entity/Name";
        private const string EntityXPath = "/ImportExportXml/Entities/Entity";
        private const string ISVConfigXPath = "/ImportExportXml/IsvConfig";
        private const string SiteMapXPath = "/ImportExportXml/SiteMap";

        List<AutoResetEvent> _events = new List<AutoResetEvent>();
        string _entityName;
        string _eventName;
        List<string> _includedScripts = new List<string>();

        // ===================== Properties ========================

        public CrmService Service { get; private set; }
        public XmlDocument ProjectFile { get; set; }
        public Services.Customizations Customization { get; private set; }

        // ===================== Methods ===========================

        #region Construction
        /// <summary>
        /// Script Uploader constructor
        /// </summary>
        /// <param name="service">Valid reference to CrmService</param>
        public ScriptUploader(CrmService service)
        {
            this.Service = service;
            this.Customization = new Services.Customizations(this.Service);
          
            // Init customizations xml
            // this.InitCustomizationXML();
        }
        private void InitCustomizationXML()
        {
            _customizations = new XElement("ImportExportXml",
          new XAttribute("version", "4.0.0.0"),
          new XAttribute("languagecode", "1033"),
          new XAttribute("generatedBy", "VS"),

          new XElement("Entities"),
          new XElement("Roles"),
          new XElement("Workflows"),

          new XElement("EntityMaps"),
          new XElement("EntityRelationships"),
          new XElement("Languages",
              new XElement("Language", "1033")));
        }
        #endregion

        #region ExportFromCRM
        public bool ExportFromCRM(string fileName)
        {
            var file = new Model.CustomizationFile(fileName);
            if (!file.Exists || !file.IsXml)
                return false;

            string request = GetExportRequestXml(file);
            if (!String.IsNullOrEmpty(request))
            {
                // Save exported customization to file
                using (FileStream fsc = new FileStream(fileName, FileMode.OpenOrCreate))
                {
                    StreamWriter fscWriter = new StreamWriter(fsc);
                    fscWriter.Write(this.Customization.Export(request));
                    fscWriter.Close();
                }
                return true;
            }

            return false;
        }
        #endregion

        #region GetExportRequestXml
        private string GetExportRequestXml(Model.CustomizationFile file)
        {
            // Build Xml doc to be sure that everythig is escaped and valid
            XDocument doc = new XDocument();
            
            if (file.IsEntity)
            {
                doc.Add(new XElement("importexportxml", new XElement("entities",
                        new XElement("entity", file.Title))));
            }
            else if (file.IsExtension)
            {
                doc.Add(new XElement("importexportxml", new XElement("nodes",
                        new XElement("node", file.Title))));
            }
            else if (file.IsSecurityRole)
            {
                doc.Add(new XElement("importexportxml", new XElement("securityroles",
                    new XElement("securityrole", file.Title))));
            }
            else if (file.IsWorkflow)
            {
                doc.Add(new XElement("importexportxml", new XElement("workflows",
                    new XElement("workflow", file.Title))));
            }
            else throw new Exceptions.NotSupportedDirectoryName();

            return doc.ToString(SaveOptions.DisableFormatting);
        }
        #endregion

        #region AppendToCustomizations
        public bool AppendToCustomizations(string fileName)
        {
            bool result = false;

            FileInfo fi = new FileInfo(fileName);


            if (fi.Exists)
            {
                XDocument doc = XDocument.Load(fi.FullName);

                foreach (XElement node in doc.Root.Elements().Where(d => d.Name != "Languages"))
                {
                    IEnumerable<XElement> Elements = _customizations.Elements(node.Name);
                    if (Elements.Count() == 1)
                    {
                        _customizations.Elements(node.Name).First().Add(node.Elements());
                    }
                }

                if (doc.Root.Elements("Templates").Count() != 0)
                {
                    _customizations.Element("Workflows").AddAfterSelf(doc.Root.Elements("Templates"));
                }

                if (doc.Root.Elements("IsvConfig").Count() != 0)
                {
                    if (_customizations.Element("Templates") != null)
                        _customizations.Element("Templates").AddAfterSelf(doc.Root.Elements("IsvConfig"));
                    else if (_customizations.Element("SiteMap") != null)
                        _customizations.Element("SiteMap").AddBeforeSelf(doc.Root.Elements("IsvConfig"));
                    else
                        _customizations.Element("EntityMaps").AddBeforeSelf(doc.Root.Elements("IsvConfig"));

                }

                if (doc.Root.Elements("SiteMap").Count() != 0)
                {
                    _customizations.Element("EntityMaps").AddBeforeSelf(doc.Root.Elements("SiteMap"));
                }
            }

            return result;
        }
        #endregion

        #region PushCustomizations
        public bool PushCustomizations(bool publishScript)
        {

            bool result = false;
            try
            {
                XElement importRequest = new XElement("importexportxml",
                    new XElement("entities"),
                    new XElement("nodes"),
                    new XElement("securityroles"),
                    new XElement("settings"),
                    new XElement("workflows"));

                IEnumerable<String> entityNames = from e in _customizations.Element("Entities").
                Elements("Entity").Elements("Name")
                                                  where !String.IsNullOrEmpty(e.Value)
                                                  select e.Value;



                foreach (string name in entityNames)
                {
                    importRequest.Element("entities").Add(new XElement("entity", name));
                }

                if (_customizations.Descendants("IsvConfig").Count() > 0)
                {
                    importRequest.Element("nodes").Add(new XElement("node", "isvconfig"));
                }


                if (_customizations.Descendants("SiteMap").Count() > 0)
                {
                    importRequest.Element("nodes").Add(new XElement("node", "sitemap"));
                }

                result = this.Customization.Import(importRequest.ToString(), _customizations.ToString());
                //if (publishScript)
                //     result = PublishCustomization(importRequest.ToString());
            }
            catch (Exception ex)
            {
                throw ex;
            }
            finally
            {
                InitCustomizationXML();
            }
            return result;

        }
        #endregion

        #region UploadCustomizationToCRM
        public bool UploadCustomizationToCRM(string fileName, bool publishScript)
        {
            bool result = false;

            FileInfo fi = new FileInfo(fileName);

            XmlDocument doc = new XmlDocument();

            if (fi.Exists)
            {
                doc.Load(fi.FullName);
                string xmlRequestParam = string.Empty;

                XmlNode entityNode = doc.SelectSingleNode("/ImportExportXml/Entities/Entity/Name");
                if (entityNode != null)
                {
                    xmlRequestParam = string.Format(FORMAT_IMPORT_EPORT_PARAM,
                        String.Format("<entity>{0}</entity>", entityNode.InnerText),
                        String.Empty,
                        String.Empty);
                }
                else
                {
                    XmlNode isvNode = doc.SelectSingleNode("/ImportExportXml/IsvConfig");
                    if (isvNode != null)
                    {
                        xmlRequestParam = string.Format(FORMAT_IMPORT_EPORT_PARAM,
                            String.Empty, "<node>isvconfig</node>", String.Empty);
                    }
                    else
                    {
                        XmlNode siteMapNode = doc.SelectSingleNode("/ImportExportXml/SiteMap");
                        if (siteMapNode != null)
                        {
                            xmlRequestParam = string.Format(FORMAT_IMPORT_EPORT_PARAM,
                                String.Empty, "<node>sitemap</node>", String.Empty);
                        }

                    }
                }

                if (!String.IsNullOrEmpty(xmlRequestParam))
                {
                    result = this.Customization.Import(xmlRequestParam, doc.OuterXml);
                    if (publishScript)
                        result = this.Customization.Publish(xmlRequestParam);
                }
            }

            return result;
        }
        #endregion

        #region ImportAllCustomizationXML
        public bool ImportAllCustomizationXML(string targetPath)
        {
            bool retValue = false;
            DirectoryInfo targetDir = new DirectoryInfo(targetPath);
            if (!targetDir.Exists)
            {
                Console.Out.WriteLine("Path couln't be found");
                return false;
            }

            FileInfo[] files = targetDir.GetFiles("*.xml");
            foreach (FileInfo file in files)
            {
                retValue = retValue & UploadCustomizationToCRM(file.FullName, false);
            }
            foreach (DirectoryInfo subdir in targetDir.GetDirectories())
            {
                retValue = retValue & ImportAllCustomizationXML(subdir.FullName);
            }

            return retValue;
        }
        #endregion

        #region ExportAllCustomizationXML
        public bool ExportAllCustomizationXML(string targetPath, string TestEntityName)
        {
            DirectoryInfo targetDir = new DirectoryInfo(targetPath);
            if (!targetDir.Exists)
            {
                targetDir.Create();
            }

            if (!String.IsNullOrEmpty(TestEntityName))
            {
                this.ProjectFile.Load(String.Format(@"{0}\{1}", targetDir, TestEntityName));
            }


            //Gettin list of customizable Entities
            ExportAllXmlRequest request = new ExportAllXmlRequest();

            ExportAllXmlResponse response = Service.Execute(request) as ExportAllXmlResponse;
            _exportedCustomisations = response.ExportXml;

            XmlDocument doc = new XmlDocument();
            doc.XmlResolver = null;
            doc.LoadXml(response.ExportXml);

            //Creating customization files for entities
            DirectoryInfo entityDir = new DirectoryInfo(targetDir.ToString() + "\\Entities");
            if (!entityDir.Exists)
            {
                entityDir.Create();
            }
            XmlNodeList entities = doc.SelectNodes("ImportExportXml/Entities/Entity[EntityInfo/entity/IsCustomizable=1]");
            foreach (XmlNode entity in entities)
            {
                AutoResetEvent evnt = new AutoResetEvent(false);
                _events.Add(evnt);
                ThreadPool.QueueUserWorkItem(
                    new WaitCallback(WriteEntityCustomizationToFile),
                    new EntityFile() { EntityXml = entity, TargetPath = entityDir.ToString(), Event = evnt });

                if (_events.Count > 3)
                {
                    WaitHandle.WaitAll(_events.ToArray());
                    _events.Clear();
                }
            }


            DirectoryInfo extDir = new DirectoryInfo(targetDir.ToString() + "\\Extentions");
            if (!extDir.Exists)
            {
                extDir.Create();
            }
            FileStream fsIsvConfig = new FileStream(String.Format(@"{0}\{1}.xml", extDir, "ISV.Config"), FileMode.OpenOrCreate);
            StreamWriter fsIsvConfigWriter = new StreamWriter(fsIsvConfig);
            fsIsvConfigWriter.Write(GetExtentionsCustomization("isvconfig"));
            fsIsvConfigWriter.Close();
            fsIsvConfig.Close();

            FileStream fsSitemap = new FileStream(String.Format(@"{0}\{1}.xml", extDir, "sitemap"), FileMode.OpenOrCreate);
            StreamWriter fsSitemapWriter = new StreamWriter(fsSitemap);
            fsSitemapWriter.Write(GetExtentionsCustomization("sitemap"));
            fsSitemapWriter.Close();
            fsSitemap.Close();

            FileStream fsTemplates = new FileStream(String.Format(@"{0}\{1}.xml", extDir, "templates"), FileMode.OpenOrCreate);
            StreamWriter fsTemplatesWriter = new StreamWriter(fsTemplates);
            fsTemplatesWriter.Write(GetExtentionsCustomization("templates"));
            fsTemplatesWriter.Close();
            fsTemplates.Close();

            AutoResetEvent[] waitEvents = _events.ToArray();
            WaitHandle.WaitAll(waitEvents);
            _events.Clear();
            using (XmlTextWriter tw = new XmlTextWriter(String.Format(@"{0}\{1}", targetDir, TestEntityName), Encoding.Default))
            {
                this.ProjectFile.WriteTo(tw);
            }
            return true;
        }
        #endregion

        #region WriteEntityCustomizationToFile
        private void WriteEntityCustomizationToFile(object entiyInfo)
        {
            EntityFile entity = entiyInfo as EntityFile;

            try
            {
                string entityName = entity.EntityName;
                string customization = GetEntityCustomization(entityName);

                using (FileStream fs = new FileStream(String.Format(@"{0}\{1}.xml", entity.TargetPath, entityName), FileMode.Create))
                {
                    StreamWriter writer = new StreamWriter(fs);
                    writer.Write(customization);
                    writer.Close();
                }

                XmlDocument customizationXML = new XmlDocument();
                customizationXML.LoadXml(customization);
                CreateScriptFile("onload", customizationXML, String.Format(@"{0}.xml.onload.js", entityName), entity.TargetPath);
                CreateScriptFile("onsave", customizationXML, String.Format(@"{0}.xml.onsave.js", entityName), entity.TargetPath);

                string[] depenants = new string[] { String.Format(@"{0}.xml.onload.js", entityName), String.Format(@"{0}.xml.onsave.js", entityName) };

                _projectHandler.AddFileToProject("Entities", String.Format("{0}.xml", entityName), depenants);
                
            }
            catch (Exception ex)
            {
                string s = ex.Message;
            }
            finally
            {
                if (entity != null && entity.Event != null)
                {
                    entity.Event.Set();
                }
            }
        }

         
        #endregion

        #region CreateScriptFile
        private void CreateScriptFile(string eventName, XmlDocument customizationXML, string fileName, string filePath)
        {
            using (FileStream fs = new FileStream(filePath + "\\" + fileName, FileMode.Create))
            {
                string script = "";
                XmlNode scriptNode = customizationXML.SelectSingleNode(String.Format("//forms/entity/form[@type='main']/events/event[@name=\"{0}\"]/script", eventName));
                if (scriptNode != null)
                    script = HttpUtility.HtmlDecode(scriptNode.InnerText);

                StreamWriter writer = new StreamWriter(fs);
                writer.Write(script);
                writer.Close();
            }

            
        }
        #endregion

        #region LoadCustomizations
        public void LoadCustomizations()
        {
            _exportedCustomisations = Customization.ExportAll();
        }
        #endregion

        #region GetEntityCustomization
        public string GetEntityCustomization(string name)
        {
            XElement customisations = XElement.Parse(_exportedCustomisations);
            customisations.Element("Entities").Elements("Entity").Where(en => en.Element("Name").Value != name).Remove();
            customisations.Element("Roles").Elements().Remove();
            customisations.Element("Workflows").Elements().Remove();
            customisations.Element("EntityMaps").Elements("EntityMap").Where(en => en.Element("EntitySource").Value != name
            && en.Element("EntityTarget").Value != name).Remove();

            customisations.Element("EntityRelationships").Elements("EntityRelationship").
                Where(en => (en.Element("EntityRelationshipType").Value != "ManyToMany" && en.Element("ReferencingEntityName").Value != name
                            && en.Element("ReferencedEntityName").Value != name)
                            || (en.Element("EntityRelationshipType").Value == "ManyToMany" && en.Element("FirstEntityName").Value != name
                            && en.Element("SecondEntityName").Value != name)).Remove();

            customisations.Element("Templates").Remove();
            customisations.Element("IsvConfig").Remove();
            customisations.Element("SiteMap").Remove();
            customisations.Element("OrganizationSettings").Remove();

            return customisations.ToString();
            //string xmlRequestParam = string.Format(FORMAT_IMPORT_EPORT_PARAM,
            //     String.Format("<entity>{0}</entity>", name),
            //     String.Empty,
            //     String.Empty);
            //return  ExportFromCRM(xmlRequestParam);
        }
        #endregion

        #region GetWorkflowCustomization
        public string GetWorkflowCustomization(string workflowGUID)
        {
            string xmlRequestParam = string.Format(FORMAT_IMPORT_EPORT_PARAM,
                String.Empty,
                String.Empty,
                String.Format("<workflow>{0}</workflow>", workflowGUID));
            return Customization.Export(xmlRequestParam);
        }
        #endregion

        #region GetExtentionsCustomization
        public string GetExtentionsCustomization(string configGUID)
        {
            string xmlRequestParam = string.Format(FORMAT_IMPORT_EPORT_PARAM,
                String.Empty,
                String.Format("<node>{0}</node>", configGUID),
                String.Empty);
            return Customization.Export(xmlRequestParam);
        }
        #endregion

        #region ExportTemplates
        private void ExportTemplates(XmlNodeList templates, string idXPath, string nameXpath, string targetPath)
        {
            DirectoryInfo targetDir = new DirectoryInfo(targetPath);
            if (!targetDir.Exists)
            {
                targetDir.Create();
            }

            foreach (XmlNode template in templates)
            {

                string templateGUID = template.SelectSingleNode(idXPath).InnerText;
                string templateName = template.SelectSingleNode(nameXpath).InnerText;
                string customization = GetExtentionsCustomization(templateGUID);

                FileStream fs = new FileStream(String.Format(@"{0}\{1}.xml", targetDir, templateName), FileMode.OpenOrCreate);
                StreamWriter writer = new StreamWriter(fs);
                writer.Write(customization);
                fs.Close();
            }
        }
        #endregion

        #region UploadScript
        private bool UploadScript(string script, bool publishScript)
        {
            bool retVal = false;
            string xmlRequestParam = string.Format(FORMAT_IMPORT_EPORT_PARAM,
                String.Format("<entity>{0}</entity>", _entityName),
                String.Empty,
                String.Empty);


            XmlDocument doc = new XmlDocument();
            doc.XmlResolver = null;
            doc.LoadXml(Customization.Export(xmlRequestParam));

            retVal = SetCustomizationScript(script, retVal, doc, _entityName, _eventName);

            if (retVal)
            {
                retVal = this.Customization.Import(xmlRequestParam, doc.OuterXml);
            }

            if (retVal && publishScript)
            {
                retVal = this.Customization.Publish(xmlRequestParam);
            }

            return retVal;
        }
        #endregion

        #region SetCustomizationScript
        public bool SetCustomizationScript(string script, bool retVal, XmlDocument doc, string entityName, string eventName)
        {
            XmlNode formNode = doc.SelectSingleNode(
                         String.Format("//forms/entity[@name='{0}']/form[@type='main']", entityName));

            XmlNode eventsNode = null;
            XmlNode scriptNode = null;

            if (formNode != null)
            {
                eventsNode = formNode.SelectSingleNode("events");
                if (eventsNode == null)
                {
                    eventsNode = doc.CreateElement("events");
                    formNode.AppendChild(eventsNode);
                }
                scriptNode = eventsNode.SelectSingleNode(String.Format("event[@name=\"{0}\"]/script", eventName));

                if (scriptNode != null && string.IsNullOrEmpty(script.Trim()))
                {
                    scriptNode.Attributes["active"].Value = "false";
                }

                if (!string.IsNullOrEmpty(script.Trim()))
                {
                    if (scriptNode == null)
                    {
                        XmlElement eventNode = doc.CreateElement("event");
                        eventNode.Attributes.Append(XmlAttribute(doc, "name", eventName));
                        eventNode.Attributes.Append(XmlAttribute(doc, "application", "false"));
                        eventNode.Attributes.Append(XmlAttribute(doc, "active", "true"));
                        scriptNode = doc.CreateElement("script");
                        XmlElement dependency = doc.CreateElement("dependencies");
                        eventNode.AppendChild(scriptNode);
                        eventNode.AppendChild(dependency);
                        eventsNode.AppendChild(eventNode);
                    }
                    XmlCDataSection scriptSection = doc.CreateCDataSection(HttpUtility.HtmlEncode(script));
                    if (scriptNode.HasChildNodes)
                    {
                        scriptNode.RemoveAll();
                    }
                    scriptNode.AppendChild(scriptSection);
                }

                retVal = true;
            }
            return retVal;
        }

        
        private XmlNode GetScriptMetaData(string script, bool isEntityScript)
        {
            string regex = @"/\*\s*(?'scriptmetadata'(?:<\s*\bscript\b\s*(?:(?:[^/]*\bentity\b\s*=\s*""
(?'entity'[^/""]*)""[^/]*\bevent\b\s*=\s*""(?'event'[^/""]*)""){1}|
(?:[^/]*\bevent\b\s*=\s*""(?'event'[^/""]*)""[^/]*\bentity\b\s*=\s*""(?'entity'[^/""]*)""){1}
|[^/]*)[^/]*>\s*(?'refs'<\s*\bref\b[^/>]*/>\s*)*\s*</\s*\bscript\b\s*>)
|(?:<\s*\bscript\b.*(?:(?:event\s*={1}\s*""(?'event'\bonload\b|\bonsave\b){1}""
\s+.*entity\s*={1}\s*""(?'entity'[^""\s]*)""){1}|(?:\s*={1}\s*""(?'entity'[^""]*)""
\s+.*event\s*={1}\s*""(?'event'\bonload\b|\bonsave\b){1}""){1})[^/]* 
(?:/>){1}))[^/]*(?:\*/){1,}";
            RegexOptions options = (((RegexOptions.IgnorePatternWhitespace | RegexOptions.Singleline)
                        | RegexOptions.Multiline)
                        | RegexOptions.IgnoreCase);
            Regex reg = new Regex(regex, options);

            MatchCollection scriptHeader = reg.Matches(script);

            XmlDocument scriptMetadatXML = new XmlDocument();
            if (scriptHeader.Count > 0)
            {
                scriptMetadatXML.LoadXml(scriptHeader[0].Groups["scriptmetadata"].Value);
                if (isEntityScript && !String.IsNullOrEmpty(scriptHeader[0].Groups["entity"].Value) && !String.IsNullOrEmpty(scriptHeader[0].Groups["event"].Value))
                {
                    _eventName = scriptHeader[0].Groups["event"].Captures[0].Value;
                    _entityName = scriptHeader[0].Groups["entity"].Captures[0].Value;
                }
                else if (isEntityScript)
                    throw new InvalidDataException("Invalid script Header");
            }
            return scriptMetadatXML.DocumentElement;
        }

        private string GetReferencesFromCode(string code)
        {
            Regex regex = new Regex(@".*(?'ref'<ref+.+src+\s*=\s*""[^""]*""*\s*.*/>)");
            MatchCollection refs = regex.Matches(code);
            StringBuilder refXml = new StringBuilder();

            refXml.Append("<refs>");
            foreach (Match match in refs)
            {
                foreach (Capture text in match.Groups["ref"].Captures)
                {
                    refXml.Append(text.Value);
                }
            }
            refXml.Append("</refs>");
            return refXml.ToString();
        }

        private string GetScriptInfoFromCode(string code)
        {


            //<script.*(?:(?:event\s*={1}\s*"(?'event'[^"]*)"\s+.*entity\s*={1}\s*"(?'entity'[^"]*)"){1}|.*(?:\s*={1}\s*"(?'entity'[^"]*)"\s+.*event\s*={1}\s*"(?'event'[^"]*)"){1}){1}(?:(?:[^/<]*/>)|(?:[^/]*>
            //.*\n*.*\n*(?:</script>){1}))

            Regex regex = new Regex(@".*(?'script'<script+.+entity+\s*=\s*""[^""]*""*\s*.*/>)");
            MatchCollection refs = regex.Matches(code);
            StringBuilder refXml = new StringBuilder();

            refXml.Append("<refs>");
            foreach (Match match in refs)
            {
                foreach (Capture text in match.Groups["ref"].Captures)
                {
                    refXml.Append(text.Value);
                }
            }
            refXml.Append("</refs>");
            return refXml.ToString();
        }

        #region GetService
        /// <summary>
        /// Instantiates ICrmService reference
        /// </summary>
        /// <returns>ICrmService reference</returns>
        public static CrmService GetService()
        {
            CrmService service = new CrmService();
            service.Url = Properties.Settings.Default.CRMService;
            service.Credentials = System.Net.CredentialCache.DefaultCredentials;
            service.PreAuthenticate = true;
            service.CrmAuthenticationTokenValue = new CrmAuthenticationToken()
            {
                OrganizationName = Properties.Settings.Default.OrgName
            };

            return service; 
        }
        #endregion

        public static CrmSDKMetadata.MetadataService GetMetaService()
        {
            CrmSDKMetadata.MetadataService service = new CrmSDKMetadata.MetadataService();
            CrmSDKMetadata.CrmAuthenticationToken token = new CrmSDKMetadata.CrmAuthenticationToken();
            token.OrganizationName = Properties.Settings.Default.OrgName;
            service.CrmAuthenticationTokenValue = token;

            service.Credentials = System.Net.CredentialCache.DefaultCredentials;

            service.PreAuthenticate = true;

            CrmSDKMetadata.RetrieveEntityRequest r = new CrmSDKMetadata.RetrieveEntityRequest();
            r.EntityItems = CrmSDKMetadata.EntityItems.EntityOnly;
            r.MetadataId = new Guid("{CC8098B7-1228-4752-99A7-2EF41A0D119F}");
            CrmSDKMetadata.RetrieveEntityResponse rr = service.Execute(r) as CrmSDKMetadata.RetrieveEntityResponse;
            return service;
        }


        private XmlAttribute XmlAttribute(XmlDocument xmlDoc, string attributeName,
                                          string attributeValue)
        {
            XmlAttribute xmlAttrib =
                xmlDoc.CreateAttribute(attributeName);
            xmlAttrib.Value = FilterXMLString(attributeValue);
            return xmlAttrib;
        }

        private string FilterXMLString(string inputString)
        {
            string returnString = inputString;
            if (inputString.IndexOf("&") > 0)
            {
                returnString = inputString.Replace("&", "&");
            }
            if (inputString.IndexOf("'") > 0)
            {
                returnString = inputString.Replace("'", "&apos;");
            }
            return returnString;
        }




        #endregion

        
    }
}
